/*global $, jQuery, window, LOCK5MAIN */

$( function() {
    // global objects
    LOCK5MAIN.histogramTypes = ["proportion", "count"];
    LOCK5MAIN.histograms = {};
    $.each(LOCK5MAIN.histogramTypes, function(i, type) {
        LOCK5MAIN.histograms[type] = $.createHistogram({
            raggedPlot: true
        });
        LOCK5MAIN.histograms[type].type = type;
    });
    LOCK5MAIN.activeHistogram = LOCK5MAIN.histograms.proportion;
    LOCK5MAIN.hypothesisTest = true;

    LOCK5MAIN.editDataDialog = ( function() {

        var clearErrors, addErrorMessage, dataEditor, editorText;
        editorText = "<div><p>Please select values for two categories of count and n.</p><table>";
        editorText = editorText +"<tr><td><label for='count1'>Group 1 count:</label></td><td><input type='text' name='count1' id='count1' value='' /></td></tr>";
        editorText = editorText +"<tr><td><label for='n1'>Group 1 n:</label></td><td><input type='text' name='n1' id='n1' value='' /></td></tr>";
        editorText = editorText +"<tr><td><label for='count2'>Group 2 count:</label></td><td><input type='text' name='count2' id='count2' value='' /></td></tr>";
        editorText = editorText +"<tr><td><label for='n2'>Group 2 n:</label></td><td><input type='text' name='n2' id='n2' value='' /></td></tr>";
        editorText = editorText +"</table><\/div>";
        dataEditor = $(editorText);
        clearErrors = function(dialog) {
            $(".errorMessage",dialog).remove();
            $('.ui-state-error',dialog).removeClass('ui-state-error');
        };
        addErrorMessage = function(id,message) {
            $(id,dataEditor).addClass('ui-state-error');
            $(id,dataEditor).parent().after("<td><p class='errorMessage ui-state-error-text'>"+message+"</p></td>");
        };
        dataEditor.appendTo('body');
        $(dataEditor).dialog({
            autoOpen: false,
            modal: true,
            open: function() {
                clearErrors(dataEditor);
            },
            buttons: [{
                text: "Ok",
                click: function () {
                    var count1, n1, count2, n2, valid, integerRe = /^-?\d\d*$/;
                    clearErrors(dataEditor);
                    count1 = $("#count1",dataEditor).val();
                    n1 = $("#n1",dataEditor).val();
                    count2 = $("#count2",dataEditor).val();
                    n2 = $("#n2",dataEditor).val();
                    valid = true;

                    if (integerRe.test(n1)) {
                        n1 = parseInt(n1,10);
                        if (n1 <= 0) {
                            addErrorMessage("#n1","Enter positive integers");
                            valid = false;
                        }
                    } else {
                        valid = false;
                        addErrorMessage("#n1","Enter integers only");
                    }

                    if (integerRe.test(count1)) {
                        count1 = parseInt(count1,10);
                        if (count1 < 0) {
                            addErrorMessage("#count1","Enter positive integers");
                            valid = false;
                        } else if (count1 > n1) {
                            addErrorMessage("#count1","Enter count that is less than n");
                            valid = false;
                        }
                    } else {
                        valid = false;
                        addErrorMessage("#count1","Enter integers only");
                    }

                    if (integerRe.test(n2)) {
                        n2 = parseInt(n2,10);
                        if (n2 <= 0) {
                            addErrorMessage("#n2","Enter positive integers");
                            valid = false;
                        }
                    } else {
                        valid = false;
                        addErrorMessage("#n2","Enter integers only");
                    }

                    if (integerRe.test(count2)) {
                        count2 = parseInt(count2,10);
                        if (count2 < 0) {
                            addErrorMessage("#count2","Enter positive integers");
                            valid = false;
                        } else if (count2 > n2) {
                            addErrorMessage("#count2","Enter count that is less than n");
                            valid = false;
                        }
                    } else {
                        valid = false;
                        addErrorMessage("#count2","Enter integers only");
                    }

                    if (valid) {
                        $("#data-source-button").button({
                            label:"Custom Data"
                        });
                        LOCK5MAIN.initialize({
                            label: "Adult/Teen Text Messages",
                            data: [{
                                label: "Group 1",
                                count: count1,
                                n: n1
                            },{
                                label: "Group 2",
                                count: count2,
                                n: n2
                            }
                            ]
                        });
                        dataEditor.dialog("close");
                    }
                }
            }],
            title: "Edit data"
        }).attr("id", "dataeditordialog");

        $("button#edit-data-source-button").button().click( function() {
            dataEditor.dialog("open");
        });
        return dataEditor;
    }());
    /* Methods */

    /*
     * LOCK5MAIN.clearGraph Clears everything to do with the LOCK5MAIN
     * randomization graph including data and control settings.
     *
     * Returns true
     */
    LOCK5MAIN.clearGraph = function() {
        $.each(LOCK5MAIN.histograms, function(i, h) {
            h.clear();
        });
        LOCK5MAIN.dotPlot.setBounds({
            xaxis: LOCK5MAIN.ORIGINAL_BOUNDS.xaxis,
            yaxis: LOCK5MAIN.ORIGINAL_BOUNDS.yaxis});
        LOCK5MAIN.dotPlot.clear();
        $("#current-sample-table").empty();
        return true;
    };
    /*
     * hoverGraph: Function that is called when the mouse hovers over a
     * point on the dotplot
     *
     * parameters: id (String) the css id of the element to plot over
     */
    LOCK5MAIN.hoverGraph = function(id) {
        return function(event, pos, item) {
            if (item) {
                var generatedFrom = item.series.data[item.dataIndex][2];
                LOCK5MAIN.makeTwoCatTable("#current-sample-table", generatedFrom);
                //LOCK5MAIN.hoverPlot(id, generatedFrom);
            }
        };
    };
    /*
     * LOCK5MAIN.generateNBootStrapSamples: generates statistics from the given
     * points
     *
     * returns: Array of statistics. A statistic is an object containing
     * statistics for each input function
     *
     * parameters: dataset (Object): describes the n and count of original sample,
     * n (Integer): the number of samples to generate
     */
    LOCK5MAIN.generateNBootStrapSamples = function(dataset, n) {
        var i, sampleNumber, originalProportion, tmpCount, pointNumber, statistics = [], currentStat = [];
        // generate n boostrap samples
        for (sampleNumber = 0; sampleNumber < n; sampleNumber += 1) {
            currentStat = LOCK5MAIN.sampleFunction(dataset);
            
            statistics.push({
                count: currentStat[0].count-currentStat[1].count,
                proportion: currentStat[0].proportion-currentStat[1].proportion,
                generatedFrom: [{
                    label: dataset[0].label,
                    count: currentStat[0].count,
                    n: currentStat[0].generatedFrom.n
                },{
                    label: dataset[1].label,
                    count: currentStat[1].count,
                    n: currentStat[1].generatedFrom.n
                }]
            });
        }
        return statistics;
    };
    /*
     * generateAndPlotBootstrapSample: helper function to generate n additional
     * points and plot the current total.
     *
     * returns: true
     *
     * parameters: point (Array): the original data to sample n (Integer):
     * nubmer of points to generate slopeFunction (function): calculates the
     * slope statistic from the boostrap points correlationFunction (function):
     * calculates the correlation statistic from the boostrap points
     */
    LOCK5MAIN.generateAndPlotBootstrapSample = function(n) { //
        return function() {

            // calculate samples
            var statistics = LOCK5MAIN.generateNBootStrapSamples(LOCK5MAIN.ORIGINAL_SAMPLE, n);

            // add those samples to each histogram
            $.each(LOCK5MAIN.histograms, function(i, h) {
                h.addPoints(statistics);
            });
            // plot the bootstrap plot with the old and new samples from
            // the current active histogram
            LOCK5MAIN.dotPlot.plot("#dotplot", LOCK5MAIN.activeHistogram.histogramPoints);

            LOCK5MAIN.makeTwoCatTable("#current-sample-table", statistics[0].generatedFrom);
            return true;
        };
    };
    /*
     * LOCK5MAIN.initialize(dataset) Initializes both plots based on
     * the 1D dataset of count and n passed to it.
     *
     * returns None
     *
     * Parameters dataset (Object): contains a count and n varaible representing a 1D quantitative variable
     */
    LOCK5MAIN.initialize = function(dataset) {
        var bootstrapGraphWidth, bootstrapGraphHeight, samplePoints, sample1, sample2, menuItems;
        
        sample1 = function (points) {
            var tmpCount = [0,0], i, sample=[], 
                totalCount =  dataset.data[0].count+dataset.data[1].count, 
                totalN = dataset.data[0].n+dataset.data[1].n, index;
                
            LOCK5MAIN.raggedPlot = true;
            for (i = 0; i < totalCount; i+=1) {
                index = Math.floor(Math.random()*(totalN-tmpCount[0]-tmpCount[1])); 
                if (index < dataset.data[0].n-tmpCount[0]) {
                    tmpCount[0] += 1;
                } else {
                    tmpCount[1] += 1;
                }
            }
            for (i = 0; i <= 1; i+=1) {
                sample.push({
                    count: tmpCount[i],
                    proportion: tmpCount[i]/dataset.data[i].n,
                    generatedFrom: {
                        count: tmpCount[i],
                        n: dataset.data[i].n
                    }
                });
            }
            return sample;
        };
        sample2 = function (points, means) {
            //Resampling
            var tmpCount = [0,0], i, sample=[], 
                totalCount =  dataset.data[0].count+dataset.data[1].count, 
                totalN = dataset.data[0].n+dataset.data[1].n, totalProp, index, offsets=[], tmpProp;
                totalProp = totalCount/totalN;
            LOCK5MAIN.raggedPlot = false;
            for (i = 0; i <= 1; i+= 1) {
                offsets.push(Math.round((totalProp*dataset.data[i].n-dataset.data[i].count)/(1-totalProp)));
            }
            //bootstrap a sample
            for (i = 0; i <= 1; i+=1) {
                tmpProp = (dataset.data[i].count+offsets[i])/(dataset.data[i].n+offsets[i]);
                for (j = 0; j < dataset.data[i].n+offsets[i]; j+=1) {
                    if (Math.random() < tmpProp) {
                        tmpCount[i] += 1;
                    }
                }
            }
            
            for (i = 0; i <= 1; i+=1) {
                sample.push({
                    count: tmpCount[i],
                    proportion: tmpCount[i]/(dataset.data[i].n+offsets[i]),
                    generatedFrom: {
                        count: tmpCount[i],
                        n: dataset.data[i].n+offsets[i]
                    }
                });
            }
            return sample;
        };
        
        menuItems = [{
            label: "Reallocation",
            callback: function() {
                //permute group labels
                LOCK5MAIN.sampleFunction = sample1;
                LOCK5MAIN.clearGraph();
            }
        },{
            label: "Resampling",
            callback: function() {
                //shift datasets to common mean sample with replacement from within respective datasets
                LOCK5MAIN.sampleFunction = sample2;
                LOCK5MAIN.clearGraph();
            }
        }];
        $.createPopupMenu($("#sample-function-button"), menuItems);
        LOCK5MAIN.sampleFunction = sample1;

        LOCK5MAIN.ORIGINAL_SAMPLE = dataset.data;

        LOCK5MAIN.makeTwoCatTable("#original-sample-table", LOCK5MAIN.ORIGINAL_SAMPLE);

        // LOCK5MAIN.PIXELSPERDOT and physical width of graph determine
        // histogram buckets
        bootstrapGraphHeight = parseInt($("#dotplot").height(), 10);
        bootstrapGraphWidth = parseInt($("#dotplot").width(), 10);

        // bootstrap some initial points to determine the initial xaxis
        // bounds on graph
        samplePoints = LOCK5MAIN.generateNBootStrapSamples(LOCK5MAIN.ORIGINAL_SAMPLE, 1000);
        // set up ranges on each histogram
        $.each(LOCK5MAIN.histograms, function(type, h) {
            ( function(array) {
                h.max = $.selection(array, 0);
                h.min = $.selection(array, array.length - 1);
            }($.map(samplePoints, function(sample) {
                return sample[type];
            })));
        });
        LOCK5MAIN.ORIGINAL_BOUNDS = {
            xaxis: {
                //histogram sorts points backwards
                min: LOCK5MAIN.activeHistogram.max,
                max: LOCK5MAIN.activeHistogram.min
            },
            yaxis: {
                min: 0,
                max: Math.floor(parseInt($("#dotplot").height(), 10) / LOCK5MAIN.PIXELSPERDOT)
            }
        };
        LOCK5MAIN.dotPlot.setBounds({
            xaxis: LOCK5MAIN.ORIGINAL_BOUNDS.xaxis,
            yaxis: LOCK5MAIN.ORIGINAL_BOUNDS.yaxis});
        $.each(LOCK5MAIN.histograms, function(key, histogram) {
            histogram.k = Math.floor(bootstrapGraphWidth / LOCK5MAIN.PIXELSPERDOT);
        });
        LOCK5MAIN.clearGraph();
    };
    // set up bootstrap type pop-up menu
    $( function() {
        var highlight, callback;
        callback = function(histogram) {
            return function() {
                LOCK5MAIN.activeHistogram = histogram;
                LOCK5MAIN.dotPlot.setBounds({
                    xaxis: {
                        //histogram sorts points backwards
                        min: LOCK5MAIN.activeHistogram.max,
                        max: LOCK5MAIN.activeHistogram.min
                    },
                    yaxis: {
                        min: 0,
                        max: Math.floor(parseInt($("#dotplot").height(), 10) / LOCK5MAIN.PIXELSPERDOT)
                    }
                });
                LOCK5MAIN.dotPlot.plot("#dotplot", LOCK5MAIN.activeHistogram.histogramPoints, LOCK5MAIN.activeHistogram.graphProperties);
                highlight();
            };
        };
        highlight = function() {
            $("#dotplot").effect("highlight", {
                color: "#eee"
            }, 350);
        };
        $.createPopupMenu($("#bootstrap-type-button"), [{
            label: "$proportion_1-proportion_2$",
            callback: callback(LOCK5MAIN.histograms.proportion)
        },{
            label: "$count_1-count_2$",
            callback: callback(LOCK5MAIN.histograms.count)
        }]);
    });
    /* Initialize the application */
    $( function() {
        LOCK5MAIN.startup({
            sampleType: "Bootstrap",
            generateAndPlot: LOCK5MAIN.generateAndPlotBootstrapSample,
            graphAnnotation: function(arrowAnnotationFn, plot, xyList) {
                var meanX = $.mean(xyList, 3), meanText = Math.truncate(meanX, 3);
                arrowAnnotationFn(plot, meanX, meanText, "#000");
            },
            parseCSV: false
        });
    });
});